/***********************************************************
 * Author: 	Brandon McKune
 * E-Mail:	bmckune.cs@gmail.com
 * Date:	September 2, 2011
 * Class:	Advanced OS
 * Time:	1150 - 1325
 * Smstr:	Fall 2011
 */

#include "ClRandomizer.h"

#define RANDOM_NUM_SIZE		10

ClRandomizer* ClRandomizer::m_ptrClRandomizer = NULL;

/**
 * 	RandomNumbers Struct
 * 	Description:
 * 		Used to hold a set of random numbers that are
 * 		generated from /dev/random during runtime to
 * 		reduce the time it takes to get random numbers.
 * 	Internal Structure:
 * 		uint16_t array
 */
struct RandomNumbers{
	uint16_t uint16Arr[RANDOM_NUM_SIZE];
}SuInternalNumbers;

//Global counter for randomizer
uint16_t counter = 0;

/**
 * 	ClRandomizer Default Constructor:
 * 	Description:
 * 		This opens the /dev/random file in linux in order
 * 		to acquire a semi-truely random number from the system.
 * 		This function can only be called by the class itself.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		N/A
 */
ClRandomizer::ClRandomizer(){
	this->m_iFileHandler = open("/dev/random", O_RDONLY);

	if(this->m_iFileHandler < -1){ //error
		perror("Project could not open /dev/random.");
		exit(1);
	}

	read(this->m_iFileHandler, &SuInternalNumbers, sizeof(RandomNumbers));
}

/**
 * 	ClRandomizer Destructor:
 * 	Description:
 * 		This function closes the file being read by
 * 		ClRandomizer for random numbers.  It also frees
 * 		up the privately owned pointer to itself.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		N/A
 */
ClRandomizer::~ClRandomizer(){
	//destructor
	close(this->m_iFileHandler);

	if(this->m_ptrClRandomizer != NULL){
		delete(this->m_ptrClRandomizer);
	}
}

/**
 * 	getInstance Function:
 * 	Description:
 * 		This is used to acquire a pointer to the private object
 * 		of ClRandomizer for the singleton architecture.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		ClRandomizer* ptr
 * 			Pointer to ClRandomizer object
 */
ClRandomizer* ClRandomizer::getInstance(){
	if(m_ptrClRandomizer == NULL){
		m_ptrClRandomizer = new ClRandomizer();
	}

	return m_ptrClRandomizer;
}

/**
 * 	getRandomNum Function:
 * 	Description:
 * 		This function reads from the SuInternalNumbers structure
 * 		and returns a value from the array containing semi-random
 * 		numbers read from /dev/random.  This function increments
 * 		the global counter each read.  Once the counter reaches the
 * 		end of the array, it adds rand() to each location in the
 * 		random number array and resets counter to 0.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		uint16_t randomNum
 * 			One of the random numbers from the internal structure
 */
uint16_t ClRandomizer::getRandomNum(){
	uint16_t randomNum = SuInternalNumbers.uint16Arr[counter++];
	if(counter == RANDOM_NUM_SIZE){
		for(int i = 0; i < RANDOM_NUM_SIZE; i++){
			SuInternalNumbers.uint16Arr[i] += rand();
		}
		counter = 0;
	}

	return randomNum;
}
